﻿using System;
using System.Linq;

namespace StableDiffusionTools.Enums
{
    public class EnumUtil : ConstrainedEnumParser<Enum> { }

    public abstract class ConstrainedEnumParser<TClass> where TClass : class
    {// value type constraint S ("TEnum") depends on reference type T ("TClass") [and on struct]
        // internal constructor, to prevent this class from being inherited outside this code
        internal ConstrainedEnumParser() { }
        // Parse using pragmatic/adhoc hard cast:
        //  - struct + class = enum
        public static TEnum Parse<TEnum>(string value, bool ignoreCase = false) where TEnum : struct, TClass
        {
            return (TEnum)Enum.Parse(typeof(TEnum), value, ignoreCase);
        }
        public static bool TryParse<TEnum>(string value, out TEnum result, bool ignoreCase = false, TEnum defaultValue = default(TEnum)) where TEnum : struct, TClass // value type constraint S depending on T
        {
            var didParse = Enum.TryParse(value, ignoreCase, out result);
            if (didParse == false)
            {
                result = defaultValue;
            }
            return didParse;
        }
        public static TEnum ParseOrDefault<TEnum>(string value, bool ignoreCase = false, TEnum defaultValue = default(TEnum)) where TEnum : struct, TClass // value type constraint S depending on T
        {
            if (string.IsNullOrEmpty(value))
                return defaultValue;

            if (Enum.TryParse(value, ignoreCase, out TEnum result))
                return result;

            return defaultValue;
        }

        public static TEnum[] GetValues<TEnum>()
        {
            return (TEnum[])Enum.GetValues(typeof(TEnum));
        }

        public static TEnum[] GetValues<TEnum>(params TEnum[] exclude)
        {
            return GetValues<TEnum>().Where(f => !exclude.Contains(f)).ToArray();
        }

        public static string[] GetNames<TEnum>() where TEnum : struct, TClass
        {
            return Enum.GetNames(typeof(TEnum));
        }

        public static string GetName<TEnum>(TEnum enumValue) where TEnum : struct, TClass
        {
            return Enum.GetName(typeof(TEnum), enumValue);
        }
    }

    public class EnumUtilsUnsafe
    {
        public static TEnum Parse<TEnum>(string value, bool ignoreCase = false) //where TEnum : System.Enum
        {
            return (TEnum)Enum.Parse(typeof(TEnum), value, ignoreCase);
        }

        public static bool TryParse<TEnum>(string value, out TEnum outEnum, bool ignoreCase = false) //where TEnum : System.Enum
        {
            bool success = false;
            Type enumType = typeof(TEnum);
            TEnum resultOutEnum = default(TEnum);

            if (enumType.IsEnum)
            {
                success = true;
                resultOutEnum = (TEnum)Enum.Parse(typeof(TEnum), value, ignoreCase);
            }

            outEnum = resultOutEnum;
            return success;
        }

        public static string GetName<TEnum>(TEnum enumValue)// where TEnum : System.Enum
        {
            return Enum.GetName(typeof(TEnum), enumValue);
        }

        public static bool TryGetName<TEnum>(TEnum enumValue, out string outName)// where TEnum : System.Enum
        {
            bool success = false;
            Type enumType = typeof(TEnum);
            string resultOutName = default(string);

            if (enumType.IsEnum)
            {
                success = true;
                resultOutName = Enum.GetName(typeof(TEnum), enumValue);
            }

            outName = resultOutName;
            return success;
        }
    }
}
